package org.swingDemo;

import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;

public class FormattedTextFieldDemo extends JPanel implements PropertyChangeListener {

    // Values for the field
    private double amount = 100000;
    private double rate = 7.5;
    private int numPeriods = 30;

    // Labels to identify the field
    private JLabel amountLabel;
    private JLabel rateLabel;
    private JLabel numPeriodsLabel;
    private JLabel paymentLabel;

    // Strings for the labels
    private static String amountString = "Loan Amount: ";
    private static String rateString = "APR (%): ";
    private static String numPeriodsString = "Years: ";
    private static String paymentString = "Montyly Payment: ";

    // Fields for data entry
    private JFormattedTextField amountField;
    private JFormattedTextField rateField;
    private JFormattedTextField numPeriodsField;
    private JFormattedTextField paymentField;

    // Formats to format and parse numbers
    private NumberFormat amountFormat;
    private NumberFormat percentFormat;
    private NumberFormat paymentFormat;

    public FormattedTextFieldDemo() {
        super(new BorderLayout());
        setUpFormats();
        double payment = computePayment(amount, rate, numPeriods);

        // create the label
        amountLabel = new JLabel(amountString);
        rateLabel = new JLabel(rateString);
        numPeriodsLabel = new JLabel(numPeriodsString);
        paymentLabel = new JLabel(paymentString);

        // create the textfields and set them up
        amountField = new JFormattedTextField(amountFormat);
        amountField.setValue(new Double(amount));
        amountField.setColumns(10);
        amountField.addPropertyChangeListener("value", this);

        rateField = new JFormattedTextField(percentFormat);
        rateField.setValue(new Double(rate));
        rateField.setColumns(10);
        rateField.addPropertyChangeListener("value", this);

        numPeriodsField = new JFormattedTextField();
        numPeriodsField.setValue(new Integer(numPeriods));
        numPeriodsField.setColumns(10);
        numPeriodsField.addPropertyChangeListener("value", this);

        paymentField = new JFormattedTextField(paymentFormat);
        paymentField.setValue(new Double(payment));
        paymentField.setColumns(10);
        paymentField.setEditable(false);
        paymentField.setForeground(Color.red);

        // tell accessibility tools about label/textfield pairs
        amountLabel.setLabelFor(amountField);
        rateLabel.setLabelFor(rateField);
        numPeriodsLabel.setLabelFor(numPeriodsField);
        paymentLabel.setLabelFor(paymentField);

        // Layout the labels in the panel
        JPanel labelPanel = new JPanel(new GridLayout(0, 1));
        labelPanel.add(amountLabel);
        labelPanel.add(rateLabel);
        labelPanel.add(numPeriodsLabel);
        labelPanel.add(paymentLabel);

        // Layout the text fields in the panel
        JPanel fieldPanel = new JPanel(new GridLayout(0, 1));
        fieldPanel.add(amountField);
        fieldPanel.add(rateField);
        fieldPanel.add(numPeriodsField);
        fieldPanel.add(paymentField);

        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        add(labelPanel, BorderLayout.CENTER);
        add(fieldPanel, BorderLayout.LINE_END);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        Object source = evt.getSource();
        if (source == amountField) {
            amount = ((Number)amountField.getValue()).doubleValue();
        } else if (source == rateField) {
            rate = ((Number)rateField.getValue()).doubleValue();
        } else if (source == numPeriodsField) {
            numPeriods = ((Number)numPeriodsField.getValue()).intValue();
        }

        double payment = computePayment(amount, rate, numPeriods);
        paymentField.setValue(new Double(payment));
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("FormattedTextFieldDemo");
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new FormattedTextFieldDemo());
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            createAndShowGUI();
        });
    }

    double computePayment(double amount, double rate, int numPeriods) {
        double I, partial, denominator, answer;

        numPeriods *= 12;
        if (rate > 0.01) {
            I = rate / 100.0 / 12;
            partial = Math.pow((1 + I), (0.0 - numPeriods));
            denominator = (1 - partial) / I;
        } else {
            denominator = numPeriods;
        }

        answer = (-1 * amount) / denominator;
        return answer;
    }

    private void setUpFormats() {
        amountFormat = NumberFormat.getNumberInstance();

        percentFormat = NumberFormat.getNumberInstance();
        percentFormat.setMinimumFractionDigits(3);

        paymentFormat = NumberFormat.getCurrencyInstance();
    }
}
